package com.shitou.shitouorder.service.impl;

import com.alibaba.fastjson.JSON;
import com.shitou.shitoucommons.exception.RRException;
import com.shitou.shitoucommons.utils.AllSaltEnum;
import com.shitou.shitoucommons.utils.RespBean;
import com.shitou.shitoucommons.vo.*;
import com.shitou.shitouorder.config.RabbitMQConfig;
import com.shitou.shitouorder.entity.OrderItemEntity;
import com.shitou.shitouorder.entity.PaymentInfoEntity;
import com.shitou.shitoucommons.opfeign.MemberFeign;
import com.shitou.shitouorder.feign.SpuInfoFeign;
import com.shitou.shitouorder.service.OrderItemService;
import com.shitou.shitouorder.service.PaymentInfoService;
import com.shitou.shitouorder.utils.RedisTemplateUtil;
import com.shitou.shitouorder.utils.UUIDUtils;
import com.shitou.shitouorder.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shitou.shitoucommons.utils.PageUtils;
import com.shitou.shitoucommons.utils.Query;

import com.shitou.shitouorder.dao.OrderDao;
import com.shitou.shitouorder.entity.OrderEntity;
import com.shitou.shitouorder.service.OrderService;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 1.  提高访问速度：Redis是基于内存的高速缓存，将订单放入Redis中可以避免频繁地访问后端数据库，大大提高订单生成的速度。
 * <p>
 * 2.  避免数据丢失：Redis具有很高的数据可靠性，可以将订单数据备份到磁盘上，避免订单数据丢失的风险。
 * <p>
 * 3.  提高并发性能：在高并发情况下，多个线程同时生成订单可能会出现数据冲突的情况。将订单放入Redis中可以使用Redis的事务特性来保证数据的原子性，从而避免数据冲突。
 * <p>
 * 4.  降低数据库压力：将订单放入Redis缓存中，可以减少数据库的读写次数，降低数据库的压力。
 */

@Transactional
@Slf4j
@SuppressWarnings("all")
@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    // 订单的状态码最大值
    private final Integer ORDER_MAX_STATUS = 6;
    private final Integer ORDER_MIN_STATUS = 0;

    /**
     * 一件商品默认的成长值为50
     */
    public final static int GROWTH = 50;
    @Autowired
    private MemberFeign memberFeign;
    @Resource(name = "RedisTemplate")
    private RedisTemplate redisTemplate;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private SpuInfoFeign spuInfoFeign;
    @Autowired
    private PaymentInfoService paymentInfoService;
    @Autowired
    private RedisTemplateUtil redisTemplateUtil;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 创建订单接口
     * @param orderVo 映射类
     * @see OrderVo 可以查看对应的
     * @return RespBean
     */
    @Override
    public RespBean createOrder(OrderVo orderVo, HttpServletRequest request, HttpServletResponse response) {

        long[] spuIds = orderVo.getSpuIds();
        List<Long> list = new ArrayList<>();
        // 对商品进行库存锁定
        for (int i = 0; i < spuIds.length; i++) {
            String productToken = String.valueOf(new Sha256Hash(String.valueOf(spuIds[i]), AllSaltEnum.SALT.getSalt()));
            Integer saleCount = (Integer) redisTemplate.opsForValue().get("saleCount:" + productToken);
            if (saleCount != null && saleCount == 0) {
                redisTemplate.opsForValue().increment("saleCount:" + productToken);
                // 将可以购买的商品进行添加
                list.add(spuIds[i]);
                // 将索引中的状态设置为不可用
                rabbitTemplate.convertAndSend("PRODUCT-SELL-QUEUE", spuIds[i]);
            }
        }
        // 可购买商品被其他人抢购，进行订单生成拦截
        if (list.size() == 0) {
            log.info("当前商品已经被其他人买下了");
            throw new RRException("订单生产异常，请刷新页面重试");
        }
        // 设置商品ids
        long[] newSpuIds = new long[list.size()];
        int index = -1;
        for (Long aLong : list) {
            newSpuIds[++index] = aLong.longValue();
        }
        orderVo.setSpuIds(newSpuIds);

        try{
            // 不能买自己的商品不是 memberId spuId
            batchCheckProductIsMyself(orderVo.getMemberId(), list.toArray(new Long[0]));
            // 校验地址是否是该用户的
            checkMemberAddress(orderVo.getMemberId(), orderVo.getAddressId());
            // 检验商品的价格对不对
            checkTotalPrice(list.toArray(new Long[0]), orderVo.getPrice());
        } catch (RRException e){
            // 库存回滚
            for (Long aLong : list) {
                rollbackSaleCount(aLong);
            }
            throw new RRException(e.getMessage());
        }


        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setSpuIds(newSpuIds);
        Date date = new Date();
        RespBean respBeanMemberVo = memberFeign.getMemberVo(orderVo.getMemberId());
        MemberVo memberVo = JSON.parseObject((String) respBeanMemberVo.get("data"), MemberVo.class);
        if ( memberVo == null ){
            // 库存回滚
            for (long spuId : orderEntity.getSpuIds()) {
                rollbackSaleCount(spuId);
            }
            throw new RRException("获取用户信息失败");
        }
        RespBean respBeanAddressVo = memberFeign.getAddress(orderVo.getAddressId(), orderVo.getMemberId());
        AddressVo addressVo = JSON.parseObject((String) respBeanAddressVo.get("data"), AddressVo.class);
        if ( addressVo == null ){
            // 库存回滚
            for (long spuId : orderEntity.getSpuIds()) {
                rollbackSaleCount(spuId);
            }
            throw new RRException("获取地址信息失败");
        }

        orderEntity.setCreateTime(date);   //  创建时间
        orderEntity.setDeleteStatus(0);   // 是否删除
        orderEntity.setConfirmStatus(0);  // 是否确认收获
        orderEntity.setNote(orderVo.getOrderNote());   // 订单备注

        orderEntity.setReceiverName(addressVo.getName());  // 收货人姓名
        orderEntity.setReceiverPhone(addressVo.getPhone());  // 收货人号码
        orderEntity.setReceiverPostCode(addressVo.getPostCode());  // 收货人邮编
        orderEntity.setReceiverProvince(addressVo.getProvince());  // 省份直辖市
        orderEntity.setReceiverCity(addressVo.getCity());  // 市区
        orderEntity.setReceiverRegion(addressVo.getRegion());  // 设置县或
        orderEntity.setReceiverDetailAddress(addressVo.getDetailAddress());  // 设置详细信息

        orderEntity.setGrowth(GROWTH * orderEntity.getSpuIds().length); // 该订单产生的成长值
        orderEntity.setAutoConfirmDay(1);   // 单位为小时

        //订单状态【0->待付款；1->待发货；2->已发货；3->已完成；4->已关闭；5->无效订单】
        // 由于是二手校园内交易，所以关于物流方面一律取消
        orderEntity.setStatus(0);  // 设置为待付款状态
        orderEntity.setSourceType(0);  // 只做了web，且没有app一律为pc
        orderEntity.setPayType(0);  // 一律只有支付宝

        orderEntity.setPayAmount(orderVo.getPrice());   // 设置价格
        orderEntity.setTotalAmount(orderVo.getPrice());  // 设置价格

        orderEntity.setMemberId(orderVo.getMemberId());   // 设置会员id，归属于谁
        orderEntity.setMemberUsername(memberVo.getUsername());   // 设置会员nickname

        String orderSN = UUIDUtils.getUUID().substring(0, 24);
        orderEntity.setOrderSn(orderSN);    // 设置订单号
        baseMapper.insert(orderEntity);

        // 将订单信息存入redis中
        redisTemplate.opsForValue().set("order:" + orderSN, orderEntity);
        // 发送消息，进行附属表的生成
        String orderJson = JSON.toJSONString(orderEntity);
        rabbitTemplate.convertAndSend(RabbitMQConfig.CREATE_ORDER_ITEM_QUEUE, orderJson);
        // 进行延时消息的发送
        rabbitTemplate.convertAndSend(RabbitMQConfig.SHITOU_TTL_QUEUE, orderSN);

        log.info("订单生成成功");
        return RespBean.success().put("data", orderEntity);
    }



    @Override
    public RespBean test(OrderVo orderVo, HttpServletRequest request, HttpServletResponse response) {

        long[] spuIds = orderVo.getSpuIds();
        List<Long> list = new ArrayList<>();
        // 对商品进行库存锁定
        for (int i = 0; i < spuIds.length; i++) {
            String productToken = String.valueOf(new Sha256Hash(String.valueOf(spuIds[i]), AllSaltEnum.SALT.getSalt()));
            String key = "memberId:" + orderVo.getMemberId() + "productId:"+productToken;
            // 将商品进行上锁
            if ( redisTemplateUtil.tryCasLock(key) ){
                try{
                    Long increment = redisTemplate.opsForValue().increment("saleCount:" + productToken);
                    if ( increment > 1 ){
                        throw new RRException("");
                    }
                    // 将可以购买的商品进行添加
                    list.add(spuIds[i]);
                    // 将索引中的状态设置为不可用
                    rabbitTemplate.convertAndSend("PRODUCT-SELL-QUEUE", spuIds[i]);
                }finally {
                    // 执行完完业务，进行锁释放
                    redisTemplateUtil.deleteLock(key);
                }
            }
        }
        // 可购买商品被其他人抢购，进行订单生成拦截
        if (list.size() == 0) {
//            log.info("当前所有商品已经被其他人买下了");
//            throw new RRException("订单生产异常，请刷新页面重试");
            return RespBean.error();
        }
        // 设置商品ids
        long[] newSpuIds = new long[list.size()];
        int index = -1;
        for (Long aLong : list) {
            newSpuIds[++index] = aLong.longValue();
        }
        orderVo.setSpuIds(newSpuIds);

        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setSpuIds(newSpuIds);
        Date date = new Date();
        RespBean respBeanMemberVo = memberFeign.getMemberVo(orderVo.getMemberId());
        MemberVo memberVo = JSON.parseObject((String) respBeanMemberVo.get("data"), MemberVo.class);
        if ( memberVo == null ){
            // 库存回滚
            for (long spuId : orderEntity.getSpuIds()) {
                rollbackSaleCount(spuId);
            }
            throw new RRException("获取用户信息失败");
        }

        orderEntity.setCreateTime(date);   //  创建时间
        orderEntity.setDeleteStatus(0);   // 是否删除
        orderEntity.setConfirmStatus(0);  // 是否确认收获
        orderEntity.setNote(orderVo.getOrderNote());   // 订单备注

        orderEntity.setGrowth(GROWTH * orderEntity.getSpuIds().length); // 该订单产生的成长值
        orderEntity.setAutoConfirmDay(1);   // 单位为小时

        //订单状态【0->待付款；1->待发货；2->已发货；3->已完成；4->已关闭；5->无效订单】
        // 由于是二手校园内交易，所以关于物流方面一律取消
        orderEntity.setStatus(0);  // 设置为待付款状态
        orderEntity.setSourceType(0);  // 只做了web，且没有app一律为pc
        orderEntity.setPayType(0);  // 一律只有支付宝

        orderEntity.setPayAmount(orderVo.getPrice());   // 设置价格
        orderEntity.setTotalAmount(orderVo.getPrice());  // 设置价格

        orderEntity.setMemberId(orderVo.getMemberId());   // 设置会员id，归属于谁
        orderEntity.setMemberUsername(memberVo.getUsername());   // 设置会员nickname

        String orderSN = UUIDUtils.getUUID().substring(0, 24);
        orderEntity.setOrderSn(orderSN);    // 设置订单号
        baseMapper.insert(orderEntity);

        // 将订单信息存入redis中
        redisTemplate.opsForValue().set("order:" + orderSN, orderEntity);
        // 发送消息，进行附属表的生成
        String orderJson = JSON.toJSONString(orderEntity);
        rabbitTemplate.convertAndSend(RabbitMQConfig.CREATE_ORDER_ITEM_QUEUE, orderJson);
        // 进行延时消息的发送
        rabbitTemplate.convertAndSend(RabbitMQConfig.SHITOU_TTL_QUEUE, orderSN);

        log.info("订单生成成功: {}",orderVo.getMemberId());
        return RespBean.success().put("data", orderEntity);
    }

    /**
     * 通过状态获取用户的订单
     * @param memberOrderVo 映射类
     * @see GetMemberOrderVo
     * @return RespBean
     */
    @Override
    public RespBean getMemberOrder(GetMemberOrderVo getMemberOrderVo, HttpServletRequest request, HttpServletResponse response) {

        // 当前选择的 订单状态大于小于 订单状态数，则
        if (getMemberOrderVo.getStatus() > ORDER_MAX_STATUS) {
            // 获得该用户的所有订单
            List<OrderEntity> orderList = this.list(new QueryWrapper<OrderEntity>().eq("member_id", getMemberOrderVo.getMemberId())
                    .eq("delete_status", 0));
            return getOrder(orderList, request, response);
        }
        if (getMemberOrderVo.getStatus() < ORDER_MIN_STATUS) {
            log.error("订单状态码出错");
            throw new RRException("订单状态码异常");
        }
        // 返回相应的状态的订单
        List<OrderEntity> orderList = this.list(new QueryWrapper<OrderEntity>().eq("member_id", getMemberOrderVo.getMemberId())
                .eq("status", getMemberOrderVo.getStatus()).eq("delete_status", 0));
        // 返回获得的数据
        return getOrder(orderList, request, response);
    }


    /**
     * 获得订单调用的子方法
     * @param orderList 订单列表
     * @return RespBean
     */
    public RespBean getOrder(List<OrderEntity> orderList, HttpServletRequest request, HttpServletResponse response) {

        List<MemberOrderVo> memberOrderVoList = new ArrayList<>();
        OrderItemEntity[] productS = null;
        MemberOrderVo memberOrderVo = null;
        MemberSpuVo[] memberSpuVos = null;
        int index = -1;

        for (OrderEntity orderEntity : orderList) {
            // 构建返回列表的单个数据
            memberOrderVo = new MemberOrderVo();
            // 将订单加入进去
            memberOrderVo.setOrder(orderEntity);
            // 获得订单下的所有商品
            List<OrderItemEntity> orderItems = orderItemService.list(new QueryWrapper<OrderItemEntity>().eq("order_sn", orderEntity.getOrderSn())
                    .eq("status", 1));
            // 组装数据
            productS = new OrderItemEntity[orderItems.size()];
            memberSpuVos = new MemberSpuVo[orderItems.size()];

            index = -1;
            for (OrderItemEntity orderItem : orderItems) {
                String[] attrs = null;
                if ( orderItem.getSkuAttrsVals() == null || orderItem.getSkuAttrsVals().equals("") ){
                    attrs = null;
                }else {
                    attrs = JSON.parseObject(orderItem.getSkuAttrsVals(), String[].class);
                }
                orderItem.setAttrs(attrs);
                // 远程获取用户id通过商品id
                long[] spuIds = new long[]{orderItem.getSpuId()};
                RespBean respBean = spuInfoFeign.getMemberIds(spuIds);
                if ( respBean == null ){
                    throw new RRException("数据获取异常，请联系管理员");
                }
                FeignProductVo data = JSON.parseObject((String) respBean.get("data"), FeignProductVo.class);
                long memberId = data.getMemberIds()[0];
                // 远程获取用户id所对应得名称
                RespBean respBeanMemberVo = memberFeign.getMemberVo(memberId);
                MemberVo memberVo = JSON.parseObject((String) respBeanMemberVo.get("data"), MemberVo.class);
                if ( memberVo == null ){
                    throw new RRException("数据获取异常，请联系管理员");
                }
                MemberSpuVo memberSpuVo = new MemberSpuVo();
                memberSpuVo.setMemberId(memberId);    // 设置用户id
                memberSpuVo.setUsername(memberVo.getUsername());    // 设置用户名称

                productS[++index] = orderItem;
                memberSpuVos[index] = memberSpuVo;
            }
            // 添加
            memberOrderVo.setProducts(productS);
            memberOrderVo.setMemberSpuVos(memberSpuVos);
            memberOrderVoList.add(memberOrderVo);
        }

        return RespBean.success().put("data", memberOrderVoList);
    }


    /**
     * 获得该用户的分页数据,通过状态和参数
     * @param memberOrderVo 映射类
     * @see GetMemberOrderVo
     * @param params 分夜查询的参数
     * @return RespBean
     */
    @Deprecated
    @Override
    public RespBean getMemberOrderPage(GetMemberOrderVo memberOrderVo, Map<String, Object> params) {

        // 当前选择的 订单状态大于小于 订单状态数，则
        if (memberOrderVo.getStatus() > ORDER_MAX_STATUS) {
            IPage<OrderEntity> page = this.page(
                    new Query<OrderEntity>().getPage(params),
                    new QueryWrapper<OrderEntity>().eq("member_id", memberOrderVo.getMemberId())
                            .eq("delete_status", 0)
            );
            // 获得该用户的所有订单
            return RespBean.success().put("data", new PageUtils(page));
        }
        if (memberOrderVo.getStatus() < ORDER_MIN_STATUS) {
            log.error("订单状态码出错");
            throw new RRException("订单状态码异常");
        }
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>().eq("member_id", memberOrderVo.getMemberId())
                        .eq("status", memberOrderVo.getStatus()).eq("delete_status", 0)
        );

        return RespBean.success().put("page", new PageUtils(page));
    }


    /**
     * 删除用户的订单信息
     * @param deleteOrderVo 映射类提
     * @see DeleteOrderVo
     * @return RespBean
     */
    @Override
    public RespBean deleteOrder(DeleteOrderVo deleteOrderVo) {
        List<OrderItemEntity> orderItemEntityList = orderItemService.list(new QueryWrapper<OrderItemEntity>()
                .eq("order_sn", deleteOrderVo.getOrderSn()).eq("status", 1));
        OrderEntity order = this.getOne(new QueryWrapper<OrderEntity>()
                .eq("order_sn", deleteOrderVo.getOrderSn()).eq("member_id", deleteOrderVo.getMemberId())
                .eq("delete_status", 0));

        if (order == null) {
            String errorMsg = "订单获取失败,可能被删除或者订单号错误";
            log.error(errorMsg);
            throw new RRException(errorMsg);
        }
        OrderEntity redisOrder = (OrderEntity) redisTemplate.opsForValue().get("order:" + deleteOrderVo.getOrderSn());
        // 如果该订单下只有一个商品，那么直接进行订单和商品的删除
        if ( orderItemEntityList.size() == 1 ){
             Iterator<OrderItemEntity> iterator = orderItemEntityList.iterator();
             while( iterator.hasNext() ){
                 OrderItemEntity next = iterator.next();
                 next.setStatus(0);
                 // 如果商品没有进行支付，那么释放库存,并将redis中的order删除，因为该订单下面已经没有商品了,
                 //     订单肯定作废了=====如果redis中的订单为空，不管是否支付，都说明该订单已经完成
                 //     了他的使命，不需要在对其进行操作了
                 if ( redisOrder != null && order.getStatus() == 0 ){
                     // 释放库存
                     for (int i = 0 ; i < redisOrder.getSpuIds().length ; i ++) {
                         // 对当前删除的商品进行库存释放
                         if ( redisOrder.getSpuIds()[i] == next.getSpuId() ) {
                             rollbackSaleCount(redisOrder.getSpuIds()[i]);
                             redisOrder.setPayAmount(redisOrder.getPayAmount().subtract(next.getSkuPrice()));
                             redisOrder.setTotalAmount(redisOrder.getTotalAmount().subtract(next.getSkuPrice()));
                             order.setPayAmount(order.getPayAmount().subtract(next.getSkuPrice()));
                             order.setTotalAmount(order.getTotalAmount().subtract(next.getSkuPrice()));
                             break;
                         }
                     }
                     // 删除redis中的商品, 让死信队列进行删除即可
//                    redisTemplate.delete("order:" + redisOrder.getOrderSn());
                 }
                 // 给发布商品的会员发送站内信
                 long[] idS = new long[]{next.getSpuId()};
                 RespBean respBean = spuInfoFeign.getMemberIds(idS);
                 FeignProductVo memberInfo = JSON.parseObject(String.valueOf(respBean.get("data")), FeignProductVo.class);
                 sendOutMessaging(
                         order.getMemberId(),
                         memberInfo.getMemberIds()[0],
                         memberInfo.getNames()[0],
                         memberInfo.getProductNames()[0],
                         order.getMemberUsername());
                 orderItemService.updateById(next);
             }
             order.setDeleteStatus(1);
        // 该订单下有多项商品，只删除商品的，不删除订单
        } else if ( orderItemEntityList.size() > 1 ){
            Iterator<OrderItemEntity> iterator = orderItemEntityList.iterator();
            while (iterator.hasNext()) {
                OrderItemEntity next = iterator.next();
                if ( deleteOrderVo.getOrderItemId() == next.getId() ){
                    next.setStatus(0);
                    // 用户没有进行支付，更新redis中的订单，并释放相应的库存,如果redis中的订单为空，不管是否支付，都说明该订单已经完成
                    //      了他的使命，不需要在对其进行操作了
                    if ( redisOrder != null && order.getStatus() == 0 ){
                        List<Long> list = new ArrayList<>();
                        // 释放库存
                        for (int i = 0 ; i < redisOrder.getSpuIds().length ; i ++) {
                            if ( redisOrder.getSpuIds()[i] == next.getSpuId() ) {
                                rollbackSaleCount(redisOrder.getSpuIds()[i]);
                                redisOrder.setPayAmount(redisOrder.getPayAmount().subtract(next.getSkuPrice()));
                                redisOrder.setTotalAmount(redisOrder.getTotalAmount().subtract(next.getSkuPrice()));
                                order.setPayAmount(order.getPayAmount().subtract(next.getSkuPrice()));
                                order.setTotalAmount(order.getTotalAmount().subtract(next.getSkuPrice()));
                                continue;
                            }
                            list.add(redisOrder.getSpuIds()[i]);
                        }
                        // 更新redis中的order订单
                        long[] newSpuIds = new long[list.size()];
                        for( int i = 0 ; i < list.size(); i ++){
                            newSpuIds[i] = list.get(i).longValue();
                        }
                        redisOrder.setSpuIds(newSpuIds);
                        redisTemplate.opsForValue().set("order:" + redisOrder.getOrderSn(), redisOrder);
                    }

                    // 对当前商品发布者推送站内信
                    long[] idS = new long[]{next.getSpuId()};
                    RespBean respBean = spuInfoFeign.getMemberIds(idS);
                    FeignProductVo memberInfo = JSON.parseObject(String.valueOf(respBean.get("data")), FeignProductVo.class);
                    sendOutMessaging(
                            order.getMemberId(),
                            memberInfo.getMemberIds()[0],
                            memberInfo.getNames()[0],
                            memberInfo.getProductNames()[0],
                            order.getMemberUsername());


                    orderItemService.updateById(next);
                    break;
                }
            }
        } else {
            log.error("订单和订单项错误");
            throw new RRException("订单和订单项错误");
        }

        order.setModifyTime(new Date());
        this.updateById(order);
        // 成功返回
        return RespBean.success();
    }


    /**
     * 确认收货
     * @param orderSn 订单号
     * @returnRespBean
     */
    @Override
    public RespBean confirm(String orderSn) {
        OrderEntity order = this.getOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn));
        if (order == null) {
            return RespBean.error("订单不存在");
        }

        // 真正的减库存,发送消息到shitou-product服务进行操作
        String spuIdsString = JSON.toJSONString(order.getSpuIds());
        rabbitTemplate.convertAndSend("DECREMENT-SALECOUNT", spuIdsString);
        log.info("减库存");

        // 发送消息给会员，给用户提供成长值和一些列操作
        MemberVo memberVo = new MemberVo();
        memberVo.setMemberId(order.getMemberId());
        memberVo.setGrowth(order.getGrowth());
        memberVo.setPayAmount(order.getPayAmount());
        memberVo.setSpuIds(order.getSpuIds());
        String jsonString = JSON.toJSONString(memberVo);
        rabbitTemplate.convertAndSend("MEMBER-OPTION-QUEUE", jsonString);
        log.info("成长值");

        Date date = new Date();
        order.setModifyTime(date);   // 修改时间
        order.setReceiveTime(date);  // 收货时间
        order.setConfirmStatus(1);  // 收货状态
        // 0-待付款 1-待发货 2-待收货 3-已收货 4-已完成 5-待评价 6-无效订单
        order.setStatus(4);   // 订单状态，4 -> 已收货
        this.updateById(order);

        // 删除redis中的数据
        redisTemplate.delete("order:"+orderSn);

        return RespBean.success();
    }


    /**
     * 获得订单的详细信息
     * @param orderSn 订单id
     * @param spuId 商品id
     * @param memberId 用户id
     * @return RespBean
     */
    @Override
    public RespBean getOrderInfo(String orderSn, long spuId, long memberId) {
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        // 查询订单
        OrderEntity order = this.getOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn).eq("member_id", memberId));

        if ( order == null ){
            log.error("订单号出错");
            throw new RRException("订单或出错");
        }

        // 查询商品发布者
        RespBean respBean = spuInfoFeign.getMemberIds(new long[]{spuId});
        FeignProductVo feignProductVo = JSON.parseObject((String) respBean.get("data"), FeignProductVo.class);
        if ( feignProductVo == null ){
            log.error("获取商品发布会者失败");
            throw new RRException("获取商品发布会者失败");
        }

        // 查询支付信息
        PaymentInfoEntity paymentInfo = paymentInfoService.getOne(new QueryWrapper<PaymentInfoEntity>().eq("order_sn", orderSn));

        // 封装订单信息
        orderInfoVo.setMemberId(feignProductVo.getMemberIds()[0]);   // 卖家id
        orderInfoVo.setCreateTime(order.getCreateTime());
        orderInfoVo.setPaymentTime(order.getPaymentTime());
        orderInfoVo.setDeliveryTime(order.getDeliveryTime());
        orderInfoVo.setReceiveTime(order.getReceiveTime());
        orderInfoVo.setCommentTime(order.getCommentTime());

        orderInfoVo.setReceiverName(order.getReceiverName());
        orderInfoVo.setReceiverPhone(order.getReceiverPhone());
        orderInfoVo.setReceiverPostCode(order.getReceiverPostCode());
        orderInfoVo.setReceiverProvince(order.getReceiverProvince());
        orderInfoVo.setReceiverCity(order.getReceiverCity());
        orderInfoVo.setReceiverRegion(order.getReceiverRegion());
        orderInfoVo.setReceiverDetailAddress(order.getReceiverDetailAddress());

        if ( paymentInfo == null ){
            orderInfoVo.setAlipayTradwNo("");
        }else {
            orderInfoVo.setAlipayTradwNo(paymentInfo.getAlipayTradeNo());
        }

        return RespBean.success().put("data", orderInfoVo);
    }


    /**
     * redis商品库存回滚
     * @param spuId 商品id
     */
    private void rollbackSaleCount(long spuId){
        // 将索引中的状态设置为   启用
        rabbitTemplate.convertAndSend("PRODUCT-RELEASE-QUEUE", spuId);
        String productToken = String.valueOf(new Sha256Hash(String.valueOf(spuId), AllSaltEnum.SALT.getSalt()));
        redisTemplate.opsForValue().set("saleCount:" + productToken, 0);
    }


    /**
     * 检查该商品是否是自己的商品
     * @param memberId
     * @param spuId
     */
    public void batchCheckProductIsMyself(Long memberId, Long[] spuIds){
        if ( memberId == null || spuIds.length == 0 ){
            log.info("用户信息错误或商品错误: 用户: {}, 商品: {}", memberId, Arrays.asList(spuIds));
            throw new RRException("用户信息错误或商品错误");
        }
        RespBean respBean = spuInfoFeign.batchCheckPublisherIsMyself(memberId, spuIds);
        // 是自己的返回ture，否则falses
        if ( checkAll(respBean) ){
            throw new RRException("不能购买自己发布的商品哦!");
        }
    }


    /**
     * 校验总价格是否符合
     * @param spuids
     * @param price
     */
    public void checkTotalPrice(Long[] spuIds, BigDecimal price){
        if ( spuIds.length == 0 || price == null ){
            log.info("商品或价格出问题: spuIds: {}, price: {}", Arrays.asList(spuIds), price);
            throw new RRException("商品或价格出问题");
        }
        RespBean respBean = spuInfoFeign.checkTotalPrice(spuIds, price);
        // 总价符合返回true，否则false
        if ( !checkAll(respBean) ){
            throw new RRException("在创建订单时，数据校验异常");
        }
    }


    /**
     * 检车地址是否是用户的，以免发货出错了
     * @param memberId
     * @param addressId
     */
    private void checkMemberAddress(Long memberId, Long addressId) {
        if ( memberId == null || memberId.equals(0) || addressId == null || addressId == 0){
            log.info("用户信息错误或地址错误: spuIds: {}, addressId: {}", memberId, addressId);
            throw new RRException("用户信息或地址信息异常");
        }
        RespBean respBean = memberFeign.checkMemberAddress(memberId, addressId);
        // 因为是自己的地址，是自己的地址，返回true，不是则false
        if ( !checkAll(respBean) ){
            throw new RRException("地址信息错误");
        }
    }


    public boolean checkAll(RespBean respBean){
        if ( respBean == null ){
            throw new RRException("创建订单失败");
        }
        String data = (String) respBean.get("data");
        Boolean isMyself = Boolean.valueOf(data);
        if ( isMyself == null ){
            throw new RRException("创建订单失败");
        }
        return isMyself;
    }


    /**
     * 给发布商品会员和买家发送站内信
     * @param from
     * @param to
     */
    public void sendOutMessaging(Long from, long to, String publisherName, String productName, String memberName){
        MessageVo messageVo = new MessageVo();
        messageVo.setFrom(String.valueOf(from));
        String text =  text = "<mark style='background-color: #ef4400; color: #ffffff'>慕阳二手商城：" +
                "</mark><br>&nbsp;&nbsp;亲爱的 <mark style='background-color: #ef4400; color: #ffffff'>" +
                publisherName + "</mark><br>&nbsp;&nbsp; 您的商品 <mark style='background-color: #ef4400; color: #ffffff'>" +
                productName + " </mark> 已经被用户 <mark style='background-color: #ef4400; color: #ffffff'>" +
                memberName + "</mark> 取消购买，当前商品已重新上架!";
        messageVo.setTo(String.valueOf(to));
        messageVo.setText(text);
        messageVo.setDate(new Date());
        String jsonString = JSON.toJSONString(messageVo);
        // 推送发布者会员的站内信
        rabbitTemplate.convertAndSend("SEND-MESSAGING-QUEUE", jsonString);
        messageVo.setFrom("0");
        messageVo.setTo(String.valueOf(from));
        text = "<mark style='background-color: #ef4400; color: #ffffff'>慕阳二手商城：" +
                "</mark><br>&nbsp;&nbsp;亲爱的 <mark style='background-color: #ef4400; color: #ffffff'>" +
                memberName + "</mark><br>&nbsp;&nbsp; 您对商品 <mark style='background-color: #ef4400; color: #ffffff'>" +
                productName + " </mark> 取消了购买，当前商品已重新上架!";
        messageVo.setText(text);
        jsonString = JSON.toJSONString(messageVo);
        // 推送买家会员的站内信
        rabbitTemplate.convertAndSend("SEND-MESSAGING-QUEUE", jsonString);
    }


    /**
     * 申请退款请求
     * @param memberId 买家id
     * @param orderSn 订单号
     * @param orderItemId 该订单号下所对应的商品所组成的
     * @return
     */
    @Override
    public RespBean refund(Long memberId, String orderSn, Long orderItemId) {

        OrderEntity order = this.getOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn).eq("member_id",memberId));
        OrderItemEntity orderItem = orderItemService.getOne(new QueryWrapper<OrderItemEntity>().eq("id", orderItemId));
        // 要保证当前订单的状态处于未收货签收前
        Integer status = order.getStatus();
        if ( status >= 4 || status < 1){
            log.debug("该订单已经完成了！！不支持退款");
            throw new RRException("该订单已经完成了！！不支持退款");
        }
        long[] idS = new long[]{orderItem.getSpuId()};
        RespBean respBean = spuInfoFeign.getMemberIds(idS);
        FeignProductVo memberInfo = JSON.parseObject(String.valueOf(respBean.get("data")), FeignProductVo.class);
        // 给商品发布者发送站内信，，告知买家要退款
        MessageVo messageVo = new MessageVo();
        messageVo.setFrom(String.valueOf(order.getMemberId()));
        messageVo.setTo(String.valueOf(memberInfo.getMemberIds()[0]));
        String text =
                "        <div>" +
                "            <div>" +
                "               <mark style='background-color: #ef4400; color: #ffffff'>慕阳二手商城：" +
                "               </mark><br>&nbsp;&nbsp;亲爱的 <mark style='background-color: #ef4400; color: #ffffff'>" +
                                memberInfo.getNames()[0] + "</mark><br>&nbsp;&nbsp; "+order.getMemberUsername()+"对商品 <mark style='background-color: #ef4400; color: #ffffff'>" +
                                memberInfo.getProductNames()[0] + " </mark> 申请了退款申请，请您与之交流审核后进行操作!" +
                "           </div>" +
                "            <div id=\"refundOption\" style=\"width: 400px; height: 60px; text-align: center; line-height: 60px;\" >" +
                "                <span style=\"cursor: pointer;\"><button style=\"width: 150px; height: 30px; pointer-events: all;\" @click=\"refundOption('"+orderSn+"',"+orderItem.getId()+", true)\">同意退款</button></span>" +
                "                <span style=\"cursor: pointer;\"><button style=\"width: 150px; height: 30px; pointer-events: all;\" @click=\"refundOption('"+orderSn+"',"+orderItem.getId()+", false)\" >不同意退款</button></span>" +
                "                <textarea style=\"width: 300px; height: 90px; resize: none; outline: none;\" placeholder=\"如果拒绝请填写拒绝退款理由...\" v-model=\"refundNote\"></textarea>" +
                "            </div>" +
                "        </div>";
        messageVo.setDate(new Date());
        messageVo.setText(text);
        String jsonString = JSON.toJSONString(messageVo);
        rabbitTemplate.convertAndSend("SEND-MESSAGING-QUEUE", jsonString);

        return RespBean.success();
    }


    /**
     * 对退款请求的操作，同意退款或者不不同意退款
     * @param memberId
     * @param orderSn
     * @param orderItemId
     * @return
     */
    @Override
    public RespBean refundOption(RefundVo refundVo) {

        OrderItemEntity orderItem = orderItemService.getOne(new QueryWrapper<OrderItemEntity>().eq("id", refundVo.getOrderItemId()));
        OrderEntity order = this.getOne(new QueryWrapper<OrderEntity>().eq("order_sn", refundVo.getOrderSn()));

        // 修改站内信内容,，将该站内信设置为已经读取
        MessageVo message = new MessageVo();
        message.setFrom("0");
        message.setTo(String.valueOf(refundVo.getMemberId()));
        message.setMessagingId(refundVo.getMessagingId());
        String jsonString1 = JSON.toJSONString(message);
        rabbitTemplate.convertAndSend("SEND-MESSAGING-QUEUE", jsonString1);

        // 要保证当前订单的状态处于未收货签收前
        Integer status = order.getStatus();
        if ( status >= 4 || status < 1){
            log.debug("该订单已经完成了！！不支持退款");
            throw new RRException("该订单已经完成了！！不支持退款");
        }

        RespBean respBean = spuInfoFeign.getSpuInfoVo(orderItem.getSpuId());
        SpuInfoVo spuInfoVo = JSON.parseObject((String) respBean.get("data"), SpuInfoVo.class);

        Boolean isRefund = refundVo.getIsRefund();
        if ( isRefund ) {
            // 获得redis中的支付信息
            PayNotifyVo allNotifyVo = JSON.parseObject((String) redisTemplate.opsForValue().get("notiry:" + refundVo.getOrderSn()), PayNotifyVo.class);
            // 重新设置
            allNotifyVo.setOrderItemId(String.valueOf(refundVo.getOrderItemId()));   // 设置orderItem的id
            allNotifyVo.setOrderToken(refundVo.getOrderSn());   // 设置订单
            allNotifyVo.setTotalAmount(String.valueOf(spuInfoVo.getSkuPrice()));  // 设置退款金额
            allNotifyVo.setUsername(order.getMemberUsername());   // 设置买家用户名
            allNotifyVo.setMemberId(String.valueOf(order.getMemberId()));   // 设置买家id

            String jsonString = JSON.toJSONString(allNotifyVo);
            // 发送退款信息
            System.out.println(jsonString);
            rabbitTemplate.convertAndSend("ORDER-REFOND-QUEUE", jsonString);
            return RespBean.success("您同意了退款，请提醒买家注意查收~");
        }else {
            // 卖家拒绝退款， 给买家发送卖家拒绝站内信
            MessageVo messageVo = new MessageVo();
            messageVo.setFrom("0");
            messageVo.setTo(String.valueOf(order.getMemberId()));
            messageVo.setDate(new Date());
            String text = "卖家 " + refundVo.getUsername() + "拒绝退款 拒绝理由: <br>&nbsp;&nbsp;" + refundVo.getNote();
            messageVo.setText(text);
            String jsonString = JSON.toJSONString(messageVo);
            rabbitTemplate.convertAndSend("SEND-MESSAGING-QUEUE", jsonString);
            return RespBean.success("您拒绝了退款~~");
        }
    }


    /**
     * 通过会员id获取相应的订单信息
     * @param params
     * @param memberId
     * @return
     */
    @Override
    public RespBean queryPageByMemberId(Map<String, Object> params, Long memberId) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>().eq("member_id", memberId)
        );

        return RespBean.success().put("page",new PageUtils(page));
    }


}

/**
 * 通常情况下，平台会在收到买家的支付后，将货款从订单总额中分配至相应的卖家账户中，再由卖家
 * 自行提现或者结算至自己的银行账户中。这样可以保证卖家能够及时收到自己销售商品的款项。如果出现任何问
 * 题，卖家可以通过平台客服或者申诉渠道来解决。
 *
 *
 * 一种常见的解决方案是使用第三方支付平台，比如支付宝、微信支付等。买家支付成功后，平台会将支付的款项暂时托管，
 * 等待确认收货后再将款项分发给卖家。因此，卖家可以使用自己的支付宝或者微信支付账号接收款项。如果是线下交易，
 * 则需要卖家提供自己的银行账号等付款方式，让买家将付款直接打到卖家的账户中。但是这种方式相对来说比较繁琐，
 * 也不太安全，所以建议使用第三方支付平台来处理支付问题。
 */
